#include "rtsp_proxy_client.h"
#include <cstring>
#include <iostream>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include "event2/event.h"
#include "event2/bufferevent.h"
#include "config.h"
#include "thread_pool.h"

using namespace std;
using namespace rtsp;

RTSPProxyClient::RTSPProxyClient(struct event_base* eb, const char* camera_host, int camera_port, const char* player_host)
    : connect_port_(camera_port),
      eb_(eb),
      current_method_(RM_NONE)
{
    memcpy(camera_host_, camera_host, strlen(camera_host));
    memcpy(player_host_, player_host, strlen(player_host));
    stream_task_ = new StreamTask();
}

void RTSPProxyClient::Connect(connect_cb cb, void *cbarg)
{
    // 使用自定义的socket创建读写事件
    this->conn_cb_ = cb;
    this->conn_cbarg_ = cbarg;
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(this->camera_host_);
    sin.sin_port = htons(this->connect_port_);

    evutil_socket_t fd = socket(AF_INET, SOCK_STREAM, 0);
    this->bev_ = bufferevent_socket_new(eb_, fd, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev_, OnRead, OnWrite, OnEvent, this);
    bufferevent_enable(bev_, EV_READ | EV_WRITE);
    bufferevent_socket_connect(bev_, (struct sockaddr*)&sin, sizeof(sin));
}

int RTSPProxyClient::ExecuteMethod(const char *msg, method_cb cb, void *cbarg)
{
    current_method_ = GetRtspMethodName(msg);
    switch (current_method_) {
    case RM_OPTIONS:
        OptionsMethod(msg, cb, cbarg);
        break;
    case RM_DESCRIBE:
        DescribeMethod(msg, cb, cbarg);
        break;
    case RM_SETUP:
        SetupMethod(msg, cb, cbarg);
        break;
    case RM_PLAY:
        PlayMethod(msg, cb, cbarg);
        break;
    case RM_GET_PARAMETER:
        GetParameterMethod(msg, cb, cbarg);
        break;
    case RM_TEARDOWN:
        break;
    default:
        qCritical("当前方法未被定义");
        break;
    }
}

int RTSPProxyClient::OptionsMethod(const char* msg, method_cb cb, void *cbarg)
{
    this->event_cb_ = cb;
    this->event_cbarg_ = cbarg;
    return this->SendTo(msg);
}

int RTSPProxyClient::DescribeMethod(const char *msg, method_cb cb, void *cbarg)
{
    this->event_cb_ = cb;
    this->event_cbarg_ = cbarg;
    return this->SendTo(msg);
}

int RTSPProxyClient::SetupMethod(const char *msg, method_cb cb, void *cbarg)
{
    // 获取4个代理端口号
    pair<RTSPPort, RTSPPort> pipe_ports = Config::Get()->NextDoublePipePort();
    camera_proxy_ports_ = pipe_ports.first;
    player_proxy_ports_ = pipe_ports.second;
    this->event_cb_ = cb;
    this->event_cbarg_ = cbarg;
    player_ports_ = parser_.GetClientPort(msg);
    char out[1024] ={0};
    // 替换报文中的客户端端口
    parser_.ReplaceClientPort(msg, out, player_proxy_ports_);
    qInfo("播放器rtp端口: %d, rtcp端口: %d, 代理rtp端口: %d, 代理rtcp端口: %d",
               player_ports_.rtp_port,
               player_ports_.rtcp_port,
               player_proxy_ports_.rtp_port,
               player_proxy_ports_.rtcp_port);
    return this->SendTo(out);
}

int RTSPProxyClient::PlayMethod(const char *msg, method_cb cb, void *cbarg)
{
    this->event_cb_ = cb;
    this->event_cbarg_ = cbarg;
    return this->SendTo(msg);
}

int RTSPProxyClient::TeardownMethod(const char *msg, method_cb cb, void *cbarg)
{
    this->event_cb_ = cb;
    this->event_cbarg_ = cbarg;
    return this->SendTo(msg);
}

int RTSPProxyClient::GetParameterMethod(const char *msg, method_cb cb, void *cbarg)
{
    this->event_cb_ = cb;
    this->event_cbarg_ = cbarg;
    return this->SendTo(msg);
}

RTSPProxyClient::~RTSPProxyClient()
{
    if(bev_)
    {
        bufferevent_free(bev_);
        bev_ = NULL;
    }
    if(stream_task_)
    {
        // 从线程池中释放管线
        ThreadPool::Get()->RemoveTask(stream_task_);
        delete stream_task_;
        stream_task_ = NULL;
    }
}

void RTSPProxyClient::OnRead(bufferevent *bev, void *ctx)
{
    char buf[1024] = {0};
    int len = bufferevent_read(bev, buf, 1024);
    if(len > 0)
    {
        qInfo("摄像机消息: \r\n%s\r\n", buf);
        RTSPProxyClient *c = (RTSPProxyClient*)ctx;
        // 如果当前方法为SETUP，则创建一对UDP管线并提交给线程池
        if(RM_SETUP == c->current_method_)
        {
            c->camera_ports_ = c->parser_.GetServerPort(buf);
            qInfo("摄像机rtp端口: %d, rtcp端口: %d, 代理rtp端口: %d, 代理rtcp端口: %d\r\n",
                       c->camera_ports_.rtp_port,
                       c->camera_ports_.rtcp_port,
                       c->camera_proxy_ports_.rtp_port,
                       c->camera_proxy_ports_.rtcp_port);
            char out[1024] = {0};
            c->parser_.ReplaceServerPort(buf, out, c->camera_proxy_ports_);
            memcpy(buf, out, sizeof(out));
            c->parser_.ReplaceClientPort(buf, out, c->player_ports_);
            memcpy(buf, out, sizeof(out));
            // 初始化管线参数
            c->stream_task_->PlayerHost(c->player_host_)->CameraHost(c->camera_host_)->PlayerPorts(c->player_ports_, c->player_proxy_ports_)
                    ->CameraPorts(c->camera_ports_, c->camera_proxy_ports_);
            ThreadPool::Get()->AddTask(c->stream_task_);
        }

        c->event_cb_(c->current_method_, buf, c->event_cbarg_);
    }
}

void RTSPProxyClient::OnWrite(bufferevent *bev, void *ctx)
{

}

void RTSPProxyClient::OnEvent(bufferevent *bev, short what, void *ctx)
{
    RTSPProxyClient *c = (RTSPProxyClient*)ctx;
    if(what & BEV_EVENT_CONNECTED)
    {
        c->conn_cb_(CONNECTION, c->conn_cbarg_);
        return;
    }
    if(what & BEV_EVENT_ERROR)
    {
        c->conn_cb_(DISCONNECTION, c->conn_cbarg_);
        return;
    }
}

RtspMethodEnum RTSPProxyClient::GetRtspMethodName(const char *in)
{
    if(memcmp(in, "OPTIONS", 7) == 0)
    {
        return RM_OPTIONS;
    }
    if(memcmp(in, "DESCRIBE", 8) == 0)
    {
        return RM_DESCRIBE;
    }
    if(memcmp(in, "SETUP", 5) == 0)
    {
        return RM_SETUP;
    }
    if(memcmp(in, "PLAY", 4) == 0)
    {
        return RM_PLAY;
    }
    if(memcmp(in, "GET_PARAMETER", 13) == 0)
    {
        return RM_GET_PARAMETER;
    }
    if(memcmp(in, "TEARDOWN", 8) == 0)
    {
        return RM_TEARDOWN;
    }
    return RM_NONE;
}

int RTSPProxyClient::SendTo(const char *msg)
{
    return bufferevent_write(bev_, msg, strlen(msg));
}
